/*
 * @Author: sean_kei@163.com
 * @Date: 2021-06-08 15:07:23
 * @LastEditors: sean_kei@163.com
 * @LastEditTime: 2022-07-26 15:07:47
 */
package com.wxhandle.cleandemo.api.security;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import com.wxhandle.cleandemo.core.cache.ClaimCache;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

/**
 * @author sean.kei
 * @version 2021.05
 */
@Service
@Slf4j
public class DefaultAccessDecisionManager implements AccessDecisionManager {

    private ClaimCache userClaimCache;

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {
                userClaimCache = BeanUtil.applicationContext.getBean(ClaimCache.class);

                if (null == configAttributes || configAttributes.size() <= 0 || authentication.getAuthorities().size() == 0) {
                    return;
                 }

                 Jwt jwt = (Jwt)authentication.getPrincipal();
                 List<String> roles = jwt.getClaimAsStringList("authorities");
                 // 管理员角色直接通过
                 if(roles.contains("sa"))
                    return;

                 for(String role : roles) {
                    String[] claims = userClaimCache.get(role);
                    for (Iterator<ConfigAttribute> iterable = configAttributes.iterator(); iterable.hasNext();) {
                       String needClaim = iterable.next().getAttribute() + "";
                       for (String claim : claims) { // authentication
                        if(claim.equals(needClaim))
                             return;
                       }
                    }
                 }
                 log.warn(jwt.getSubject() + "权限不足" + configAttributes.toString());
                 throw new AccessDeniedException("没有权限访问！");
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

}
